package com.easyFramework.servlet;


import com.easyFramework.annotation.ResponseBody;
import com.easyFramework.bean.Handler;
import com.easyFramework.bean.ModelAndView;
import com.easyFramework.bean.Param;
import com.easyFramework.helper.*;
import com.easyFramework.util.*;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Map;


/**
 * Created on 2018/8/8 19:37.
 *
 * @author SinKitwah
 * @Description 请求转发器
 */
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class Dispatcher extends HttpServlet {

    //dispatcher转发器的日志
    private static final Logger LOGGER = LoggerFactory.getLogger(Dispatcher.class);

    @Override
    public void init() throws ServletException {
        //初始化相关类
        Class<?>[] classList = {
                ClassHelper.class,
                IocHelper.class,
                ControllerHelper.class
        };
        for (Class<?> cls : classList){
            ClassUtil.loadClass(cls.getName(),false);
        }
        //获取ServletContext对象（用于注册Servlet）
        ServletContext servletContext = getServletContext();
        //注册处理JSP的servlet
        ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
        jspServlet.addMapping(PropertiesUtil.getJspPath()+"*");
        //注册处理静态资源的默认Servlet
        ServletRegistration defaultServlet =  servletContext.getServletRegistration("default");
        defaultServlet.addMapping(PropertiesUtil.getStaticPath()+"*");
        //注册上传文件处理器
        UploadHelper.init(servletContext);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求路径与请求方法
        String requestPath = req.getPathInfo();
        String requestMethod = req.getMethod().toLowerCase();
        //过滤/favicon.ico
        if(requestPath.equals("/favicon.ico")) return;
        //获取RequestMapping处理器
        Handler handler = ControllerHelper.getHandler(requestMethod,requestPath);
        if (handler != null){
            //获取Controller对象
            Object controllerBean = IocHelper.getBean(handler.getControllerClass());
            Method method = handler.getRequestMappingMethod();
            Param param;
            if(UploadHelper.isMultipart(req)){
                param = UploadHelper.getParameter(req);
            }else {
                param = ParamUtil.getParameter(req);
            }
            Object[] args = ParamUtil.getMethodArgs(method,param,req,resp);
            try {
                Object result = ReflectionUtil.invokeMethod(controllerBean,method,args);
                handleResult(method,result,resp,req);
            }catch (Exception e){
                LOGGER.error("DispatcherServlet.service:handle http request failure",e);
                throw new RuntimeException(e);
            }
        }
    }

    private void handleResult(Method method,Object result,HttpServletResponse response,HttpServletRequest request) {
        if (result == null)
            return;
        //优先返回Json数据
        if (method.isAnnotationPresent(ResponseBody.class)
                ||(!(result instanceof String)&&!(result instanceof ModelAndView))) {
            //返回Json数据
            try {
                Gson gson = new Gson();
                response.setContentType("application/json");
                response.setCharacterEncoding("UTF-8");
                PrintWriter writer = response.getWriter();
                writer.write(gson.toJson(result));
                writer.flush();
                writer.close();
            } catch (Exception e) {
                LOGGER.error("DispatcherServlet.handleResult:return Json failure!", e);
                throw new RuntimeException(e);
            }
            return;
        }
        //如果返回的是JSP路径
        if (result instanceof String) {
            try {
                if (((String) result).startsWith("redirect:")){
                    response.sendRedirect(request.getContextPath()+((String) result).replace("redirect:","").trim());
                }
                request.getRequestDispatcher(PropertiesUtil.getJspPath()+result).forward(request, response);
            } catch (Exception e) {
                LOGGER.error("DispatcherServlet.setResult:return JSP failure!",e);
                throw new RuntimeException(e);
            }
            return;
        }
        //如果返回的是ModelAndView类
        if (result instanceof ModelAndView){
            ModelAndView data = (ModelAndView) result;
            if (data.getPath() != null) {
                try {
                if (data.getPath().startsWith("redirect:")){
                    response.sendRedirect(request.getContextPath()+data.getPath().replace("redirect:","").trim());
                    return;
                }
                //返回JSP页面
                Map<String, Object> model = data.getModel();
                for(Map.Entry<String, Object> entry:model.entrySet()){
                    request.setAttribute(entry.getKey(), entry.getValue());
                }
                    request.getRequestDispatcher(PropertiesUtil.getJspPath()+data.getPath()).forward(request, response);
                } catch (Exception e) {
                    LOGGER.error("DispatcherServlet.setResult:return ModelAndView failure!",e);
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
